/*
 * specobj.c - Build spec object.
 * cezanne@clunix.com, 2005.3
 *
 * Copyright (c) 2001-2005 by Clunix Inc. All Rights Reserved.
 */

#include "config.h"

#include <stdio.h>
#include <string.h>

#include "sr.h"
#include "mkentity.h"
#include "mke_err.h"
#include "mke_utils.h"

#define ENC_BUFSIZE	(4096 * 32)

sr_t *
create_sr_ETT(ecm_uint32 lineno, const char *name, ECMBOOL is_HMS, ECMBOOL is_ref, sr_t *sr_supers)
{
	sr_t	*sr = sr_create(ST_MKE_ETT);

	sr_createc_str(sr, "name", ST_STR, name);
	sr_createc_bool(sr, "HMS", ST_BOOL, is_HMS);
	sr_createc_bool(sr, "ref", ST_BOOL, is_ref);
	if (sr_supers)
		sr_addc(sr, "supers", sr_supers);
	else
		sr_createc_dir(sr, "supers");

	add_src_info(sr, lineno);
	return sr;
}

ECM_INLINE ECMBOOL
is_EPE_decl(const sr_t *sr_decl)
{
	if (sr_get_type(sr_decl) == ST_MKE_EPE_DECL)
		return ECM_TRUE;
	return ECM_FALSE;
}

ECM_INLINE ECMBOOL
is_EDE_decl(const sr_t *sr_decl)
{
	if (sr_get_type(sr_decl) == ST_MKE_EDE_DECL)
		return ECM_TRUE;
	return ECM_FALSE;
}

static ECMBOOL
is_dependent(const char *ETT_name, sr_t *sr_def, sr_t **psr_dependent)
{
	sr_t	*sr_defs, *sr_sub_def, *sr_sub_ETT;
	const char	*sub_ETT_name;

	sr_defs = sr_getc(sr_def, "defs");
	SR_FOREACH_CHILD(sr_defs, NULL, sr_sub_def) {
		sr_sub_ETT = sr_getc(sr_sub_def, "ETT");
		sub_ETT_name = sr_getc_str(sr_sub_ETT, "name");
		if (ecm_strcmp(ETT_name, sub_ETT_name) == 0 &&
		    !is_ref_sr_ETT(sr_sub_ETT)) {
			if (psr_dependent)
				*psr_dependent = sr_sub_def;
			return ECM_TRUE;
		}
		if (is_dependent(ETT_name, sr_sub_def, psr_dependent))
			return ECM_TRUE;
	}
	return ECM_FALSE;
}

static ECM_INLINE ECMBOOL
check_self_dependency(sr_t *sr_decl)
{
	sr_t	*sr_dependent;
	ECMBOOL	res;

	if (is_EPE_decl(sr_decl))
		return ECM_FALSE;
	res = is_dependent(get_decl_ETT_name(sr_decl),
			   sr_getc(sr_decl, "def"),
			   &sr_dependent);
	if (res)
		print_error(MKE_ERROR_FATAL, sr_dependent, 0, "recursive entity type");
	return res;
}

static ECMBOOL
is_inherited(const char *ETT_name, sr_t *sr_def)
{
	sr_t	*sr_ETT = sr_getc(sr_def, "ETT");
	sr_t	*sr_ETTs_super = sr_getc(sr_ETT, "supers");
	sr_t	*sr_ETT_super;

	SR_FOREACH_CHILD(sr_ETTs_super, NULL, sr_ETT_super) {
		if (ecm_strcmp(sr_getc_str(sr_ETT_super, "name"), ETT_name) == 0)
			return ECM_TRUE;
	}
	return ECM_FALSE;
}

static void
build_dependency(sr_t *sr_top_decls, sr_t *sr_decl, sr_t *sr_compared)
{
	sr_t		*sr_def;
	const char	*ETT_name, *ETT_name_compared;

	ETT_name = get_decl_ETT_name(sr_decl);
	ETT_name_compared = get_decl_ETT_name(sr_compared);

	sr_def = sr_getc(sr_decl, "def");
	if (is_dependent(ETT_name_compared, sr_def, NULL) ||
	    is_inherited(ETT_name_compared, sr_def)) {
		sr_addc(sr_getc(sr_decl, "children"),
			ETT_name_compared,
			sr_create_ptr(ST_PTR, sr_compared));
		sr_addc(sr_getc(sr_compared, "parents"),
			ETT_name,
			sr_create_ptr(ST_PTR, sr_decl));
		sr_free(sr_getc(sr_top_decls, ETT_name_compared));
	}
}

static ECMBOOL
detect_circular(const char *name, sr_t *sr_decl)
{
	sr_t	*sr_ptr, *sr_child;

	if (sr_getc(sr_getc(sr_decl, "children"), name)) {
		print_error(MKE_ERROR_FATAL, sr_decl, 0, "has a circular dependency with <%s>", name);
		return ECM_TRUE;
	}
	SR_FOREACH_CHILD(sr_decl, "children", sr_ptr) {
		sr_child = sr_get_ptr(sr_ptr);
		if (detect_circular(name, sr_child))
			return ECM_TRUE;
	}
	return ECM_FALSE;
}

static ECMBOOL
check_circular_dependency(sr_t *sr_top_decls, sr_t *sr_decls, sr_t *sr_decl)
{
	sr_t	*sr_compared;

	if (is_EPE_decl(sr_decl))
		return ECM_FALSE;
	SR_FOREACH_CHILD(sr_decls, NULL, sr_compared) {
		if (is_EPE_decl(sr_compared))
			continue;

		build_dependency(sr_top_decls, sr_decl, sr_compared);
		build_dependency(sr_top_decls, sr_compared, sr_decl);

		if (detect_circular(get_decl_ETT_name(sr_decl), sr_decl))
			return ECM_TRUE;
	}
	return ECM_FALSE;
}

static void
remove_sr_decl(sr_t *sr_decl)
{
	sr_t	*sr_parent, *sr_child;
	sr_t	*sr_ptr1, *sr_ptr2;
	const char	*name;

	name = get_decl_ETT_name(sr_decl);
	SR_FOREACH_CHILD(sr_decl, "parents", sr_ptr1) {
		sr_parent = sr_get_ptr(sr_ptr1);
		sr_ptr2 = sr_getc(sr_getc(sr_decl, "children"), name);
		sr_free(sr_ptr2);
	}
	SR_FOREACH_CHILD(sr_decl, "children", sr_ptr1) {
		sr_child = sr_get_ptr(sr_ptr1);
		sr_ptr2 = sr_getc(sr_getc(sr_decl, "parents"), name);
		sr_free(sr_ptr2);
	}
	sr_free(sr_decl);
}

sr_t *
add_entity_decl(ecm_uint32 lineno, sr_t *sr_entities, sr_t *sr_decl)
{
	sr_t		*sr_top_decls, *sr_decls;
	const char	*ETT_name;

	sr_top_decls = sr_getc(sr_entities, "top_decls");
	sr_decls = sr_getc(sr_entities, "decls");
	ETT_name = get_decl_ETT_name(sr_decl);
	if (sr_getc(sr_decls, ETT_name)) {
		print_error(MKE_ERROR_FATAL, sr_decl, 0, "duplicated entity type declaration");
		remove_sr_decl(sr_decl);
		return sr_entities;
	}

	if (check_self_dependency(sr_decl)) {
		print_error(MKE_ERROR_FATAL, sr_decl, 0, "has self dependency");
		remove_sr_decl(sr_decl);
		return sr_entities;
	}

	if (check_circular_dependency(sr_top_decls, sr_decls, sr_decl)) {
		remove_sr_decl(sr_decl);
		return sr_entities;
	}

	if (sr_entities == NULL) {
		sr_entities = sr_create_dir();
		sr_top_decls = sr_createc_dir(sr_entities, "top_decls");
		sr_decls = sr_createc_dir(sr_entities, "decls");
	}
	if (sr_get_num_child(sr_getc(sr_decl, "parents")) == 0)
		sr_addc(sr_top_decls, ETT_name, sr_create_ptr(ST_PTR, sr_decl));
	sr_append(sr_decls, sr_decl);
	return sr_entities;
}

static void
adjust_entity_decl(sr_t *sr_decls, sr_t *sr_decl)
{
	sr_t	*sr_ptr, *sr_child;
	const char	*name = get_decl_ETT_name(sr_decl);

	if (sr_getc(sr_decls, name) == NULL)
		sr_append(sr_decls, sr_decl);
	SR_FOREACH_CHILD(sr_decl, "children", sr_ptr) {
		sr_child = sr_get_ptr(sr_ptr);
		adjust_entity_decl(sr_decls, sr_child);
	}
	sr_free(sr_getc(sr_decl, "children"));
	sr_free(sr_getc(sr_decl, "parents"));
}

sr_t *
adjust_entity_decls(sr_t *sr_entities)
{
	sr_t	*sr_top_decls, *sr_decls;
	sr_t	*sr_ptr, *sr_decl;

	sr_top_decls = sr_getc(sr_entities, "top_decls");
	sr_decls = sr_getc(sr_entities, "decls");

	SR_FOREACH_CHILD(sr_top_decls, NULL, sr_ptr) {
		sr_decl = sr_get_ptr(sr_ptr);
		sr_crop(sr_decl);
		adjust_entity_decl(sr_decls, sr_decl);
	}
	sr_free(sr_top_decls);
	sr_crop(sr_decls);
	sr_free(sr_entities);

	return sr_decls;
}

void
check_ETT_desc(ecm_uint32 lineno, sr_t *sr_ETT)
{
	if (is_HMS_sr_ETT(sr_ETT)) {
		raise_error(MKE_ERROR_FATAL, lineno,
			    "entity type description cannot be homoset type");
		return;
	}
	if (is_ref_sr_ETT(sr_ETT)) {
		raise_error(MKE_ERROR_FATAL, lineno,
			    "entity type description cannot be reference type");
	}
}

void
add_super_ETTs(ecm_uint32 lineno, sr_t *sr_ETT, sr_t *sr_ETTs)
{
	sr_t	*sr_ETT_super;
	const char	*ETT_name;

	ETT_name = sr_getc_str(sr_ETT, "name");
	SR_FOREACH_CHILD(sr_ETTs, NULL, sr_ETT_super) {
		if (ecm_strcmp(sr_getc_str(sr_ETT_super, "name"), ETT_name) == 0) {
			raise_error(MKE_ERROR_FATAL, lineno,
				    "%s: same name with super entity", ETT_name);
			sr_free(sr_ETTs);
			return;
		}
	}
	sr_merge(sr_getc(sr_ETT, "supers"), sr_ETTs);
	sr_free(sr_ETTs);
}

sr_t *
add_super_ETT(ecm_uint32 lineno, sr_t *sr_ETTs, sr_t *sr_new_ETT)
{
	sr_t	*sr_ETT;
	const char	*ETT_name;

	if (sr_ETTs == NULL)
		sr_ETTs = sr_create_dir();
	ETT_name = sr_getc_str(sr_new_ETT, "name");
	SR_FOREACH_CHILD(sr_ETTs, NULL, sr_ETT) {
		if (ecm_strcmp(sr_getc_str(sr_ETT, "name"), ETT_name) == 0) {
			raise_error(MKE_ERROR_FATAL, lineno,
				    "<%s>: duplicated entity type name", ETT_name);
			sr_free(sr_ETTs);
			sr_free(sr_new_ETT);
			return NULL;
		}
	}
	sr_append(sr_ETTs, sr_new_ETT);
	return sr_ETTs;
}

sr_t *
create_EPE_decl(ecm_uint32 lineno, sr_t *sr_ETT, sr_t *sr_extra, ECMBOOL overwrite)
{
	sr_t	*sr_decl, *sr_supers;

	sr_decl = sr_create(ST_MKE_EPE_DECL);

	sr_supers = sr_getc(sr_ETT, "supers");
	if (sr_get_num_child(sr_supers) > 1) {
		raise_error(MKE_ERROR_FATAL, lineno,
			    "Multiple inheritance of primary entity is not allowed");
		sr_free(sr_ETT);
		sr_free(sr_extra);
		return NULL;
	}

	sr_set_name(sr_decl, sr_getc_str(sr_ETT, "name"));
	sr_addc(sr_decl, "def", create_entity_def(lineno, NULL, sr_ETT, NULL, NULL, NULL, ECM_FALSE));

	if (sr_extra) {
		sr_t	*sr_ETT_super;

		sr_ETT_super = sr_geti(sr_supers, 0);
		if (ecm_strcmp(sr_getc_str(sr_ETT_super, "name"), "int") != 0) {
			raise_error(MKE_ERROR_FATAL, lineno,
				    "Only extended <int> has optional body statement");
			sr_free(sr_decl);
			sr_free(sr_extra);
			return NULL;
		}
		sr_addc(sr_decl, "extra", sr_extra);
	}
	sr_createc_bool(sr_decl, "overwrite", ST_BOOL, overwrite);
	return sr_decl;
}

sr_t *
create_EDE_decl(ecm_uint32 lineno, sr_t *sr_ETT, sr_t *sr_def_block, sr_t *sr_exts, ECMBOOL overwrite)
{
	sr_t	*sr_decl, *sr_supers;
	sr_t	*sr_def;

	sr_decl = sr_create(ST_MKE_EDE_DECL);

	sr_supers = sr_getc(sr_ETT, "supers");
	if (sr_get_num_child(sr_supers) == 0)
		sr_append(sr_supers, create_sr_ETT(lineno, "dir", ECM_FALSE, ECM_FALSE, NULL));

	sr_set_name(sr_decl, sr_getc_str(sr_ETT, "name"));

	sr_def = create_entity_def(lineno, NULL, sr_ETT, NULL, sr_def_block, sr_exts, ECM_FALSE);
	sr_addc(sr_decl, "def", sr_def);

	sr_createc_dir(sr_decl, "children");
	sr_createc_dir(sr_decl, "parents");
	add_src_info(sr_decl, lineno);

	sr_createc_bool(sr_decl, "overwrite", ST_BOOL, overwrite);
	return sr_decl;
}

static ECMBOOL
check_samesig(sr_t *sr_func1, sr_t *sr_func2)
{
	sr_t	*sr_args1, *sr_args2;
	int	num_child, i;

	sr_args1 = sr_getc(sr_func1, "args");
	sr_args2 = sr_getc(sr_func2, "args");
	num_child = sr_get_num_child(sr_args1);
	if (sr_get_num_child(sr_args2) != num_child)
		return ECM_FALSE;
	for (i = 0; i < num_child; i++) {
		if (!is_same_ETT(sr_geti(sr_args1, i), sr_geti(sr_args2, i)))
			return ECM_FALSE;
	}
	return ECM_TRUE;
}

sr_t *
add_function(ecm_uint32 lineno, sr_t *sr_funcs, sr_t *sr_sig)
{
	sr_t	*sr_func_exist, *sr_sig_exist;
	const char	*funcname;

	if (sr_sig == NULL)
		return sr_funcs;

	funcname = sr_get_name(sr_sig);
	sr_func_exist = sr_getc(sr_funcs, funcname);
	if (sr_func_exist == NULL) {
		sr_t	*sr_func;

		if (sr_funcs == NULL)
			sr_funcs = sr_create_dir();
		sr_func = sr_append(sr_funcs, sr_create_dir());
		sr_set_name(sr_func, funcname);
		sr_append(sr_func, sr_sig);
		return sr_funcs;
	}
	SR_FOREACH_CHILD(sr_func_exist, NULL, sr_sig_exist) {
		if (check_samesig(sr_sig_exist, sr_sig)) {
			raise_error(MKE_ERROR_FATAL, lineno, "duplicated function signature");
			sr_free(sr_sig);
			return sr_funcs;
		}
	}
	sr_append(sr_func_exist, sr_sig);
	return sr_funcs;
}

sr_t *
create_function(ecm_uint32 lineno, func_modifier_t modifiers, sr_t *sr_ETT,
		char *funcname, sr_t *sr_args, sr_t *sr_mke_edexpr)
{
	sr_t	*sr_sig;

	sr_sig = sr_create(ST_MKE_FUNCSIG);
	sr_set_name(sr_sig, funcname);
	ecm_free(funcname);

	sr_addc(sr_sig, "args", sr_args);
	if (modifiers & FUNC_MODIFIER_AUTONOMOUS)
		sr_createc_bool(sr_sig, "autonomous", ST_BOOL, ECM_TRUE);
	if (modifiers & FUNC_MODIFIER_OVERWRITE)
		sr_createc_bool(sr_sig, "overwrite", ST_BOOL, ECM_TRUE);
	sr_addc(sr_sig, "ret", sr_ETT);
	sr_addc(sr_sig, "mke_edexpr", sr_mke_edexpr);

	add_src_info(sr_sig, lineno);

	return sr_sig;
}

func_modifier_t
add_func_modifier(ecm_uint32 lineno, func_modifier_t modifiers, func_modifier_t modifier)
{
	if (modifiers & modifier) {
		raise_error(MKE_ERROR_WARNING, lineno, "duplicated function modifier");
		return modifiers;
	}
	return (modifiers | modifier);
}

sr_t *
create_ientry(ecm_uint32 lineno, sr_t *sr_tree_path, sr_t *sr_def)
{
	const char	*path;
	sr_t	*sr_ientry;
	sr_t	*sr_LNP;

	path = sr_getc_str(sr_tree_path, "path");
	if (ecm_empty_str(path)) {
		print_error(MKE_ERROR_FATAL, sr_tree_path, 0, "empty initial tree path is not allowed");
		goto err;
	}
	sr_LNP = get_sr_LNP(path);
	if (sr_LNP == NULL) {
		print_error(MKE_ERROR_FATAL, sr_tree_path, 0, "invalid LNP");
		goto err;
	}

	if (get_LNI_idx(sr_LNP, 0, LNI_TYPE_ALL, NULL) >= 0 ||
	    get_LNI_idx(sr_LNP, 0, LNI_TYPE_ANY, NULL) >= 0) {
		print_error(MKE_ERROR_FATAL, sr_tree_path, 0, "ALL or ANY LNI is not allowed");
		sr_free(sr_LNP);
		goto err;
	}

	sr_ientry = sr_create_dir();
	sr_set_name(sr_ientry, path);

	sr_addc(sr_ientry, "LNP", get_dir_sr_LNP(sr_LNP));
	sr_setc_str(sr_def, "name", get_sr_LNP_basename(sr_LNP));
	sr_addc(sr_ientry, "def", sr_def);
	sr_free(sr_LNP);
	sr_free(sr_tree_path);
	add_src_info(sr_ientry, lineno);
	return sr_ientry;
err:
	sr_free(sr_tree_path);
	sr_free(sr_def);
	return NULL;
}

sr_t *
add_ientry(ecm_uint32 lineno, sr_t *sr_ientries, sr_t *sr_ientry)
{
	const char	*path;

	path = sr_get_name(sr_ientry);
	if (sr_getc(sr_ientries, path)) {
		raise_error(MKE_ERROR_FATAL, lineno, "%s: duplicated path", path);
		sr_free(sr_ientry);
	}
	else {
		if (sr_ientries == NULL)
			sr_ientries = sr_create_dir();
		sr_append(sr_ientries, sr_ientry);
	}
	return sr_ientries;
}

sr_t *
find_decl(sr_t *sr_decls, const char *ETT_name)
{
	return sr_getc(sr_decls, ETT_name);
}

sr_t *
create_asrv(ecm_uint32 lineno, char *ASRV)
{
	sr_t	*sr_asrv = sr_create(ST_MKE_ASRV);

	sr_addc(sr_asrv, "asrv", sr_set_val(sr_create(ST_STR), sr_val_str(ASRV)));
	add_src_info(sr_asrv, lineno);
	return sr_asrv;
}

sr_t *
create_attr(ecm_uint32 lineno, srt_t srt, sr_t *sr_asrv)
{
	sr_t	*sr_mke_attr, *sr_attr;
	const char	*asrv;

	asrv = sr_getc_str(sr_asrv, "asrv");
	sr_attr = sr_create_asrv(srt, asrv);
	if (sr_attr == NULL) {
		print_error(MKE_ERROR_FATAL, sr_asrv, 0, "invalid asrv");
		sr_free(sr_asrv);
		return NULL;
	}
	sr_free(sr_asrv);
	sr_mke_attr = sr_create(ST_MKE_ATTR);
	sr_addc(sr_mke_attr, "attr", sr_attr);

	add_src_info(sr_mke_attr, lineno);
	return sr_mke_attr;
}

sr_t *
add_ext(sr_t *sr_exts, const char *type, sr_t *sr_ext)
{
	if (sr_exts == NULL)
		return sr_create_dir();
	if (sr_getc(sr_exts, type))
		print_error(MKE_ERROR_FATAL, sr_ext, 0, "duplicated attribute");
	else
		sr_addc(sr_exts, type, sr_ext);
	return sr_exts;
}

sr_t *
create_tree_path(ecm_uint32 lineno, char *path)
{
	sr_t	*sr_tree_path;

	sr_tree_path = sr_create(ST_MKE_TREE_PATH);
	sr_addc(sr_tree_path, "path", sr_set_val(sr_create(ST_STR), sr_val_str(path)));
	add_src_info(sr_tree_path, lineno);
	return sr_tree_path;
}

sr_t *
create_entity_name(ecm_uint32 lineno, char *name)
{
	sr_t	*sr_ET_name;

	sr_ET_name = sr_create(ST_MKE_ET_NAME);
	sr_addc(sr_ET_name, "name", sr_set_val(sr_create(ST_STR), sr_val_str(name)));
	add_src_info(sr_ET_name, lineno);
	return sr_ET_name;
}

sr_t *
create_entity_def(ecm_uint32 lineno, sr_t *sr_ET_name, sr_t *sr_ETT,
		  sr_t *sr_asrv, sr_t *sr_def_block, sr_t *sr_exts,
		  ECMBOOL overwrite)
{
	sr_t	*sr_def;
	const char	*name = NULL;

	if (sr_ET_name) {
		name = sr_getc_str(sr_ET_name, "name");
		if (ecm_empty_str(name)) {
			print_error(MKE_ERROR_FATAL, sr_ET_name, 0, "empty entity name is not allowed");
			sr_free(sr_ET_name);
			sr_free(sr_ETT);
			sr_free(sr_asrv);
			sr_free(sr_def_block);
			sr_free(sr_exts);
			return NULL;
		}
	}
	sr_def = sr_create(ST_MKE_ETT_DEF);
	sr_createc_str(sr_def, "name", ST_STR, name);
	sr_free(sr_ET_name);
	sr_addc(sr_def, "ETT", sr_ETT);
	sr_addc(sr_def, "defs", sr_def_block);
	sr_addc(sr_def, "asrv", sr_asrv);
	sr_addc(sr_def, "exts", sr_exts);
	sr_createc_bool(sr_def, "overwrite", ST_BOOL, overwrite);

	add_src_info(sr_def, lineno);

	return sr_def;
}

void
add_entity_def(sr_t *sr_defs, sr_t *sr_def)
{
	sr_t	*sr_def_exist;
	const char	*name;

	name = sr_getc_str(sr_def, "name");
	SR_FOREACH_CHILD(sr_defs, NULL, sr_def_exist) {
		if (ecm_strcmp(sr_getc_str(sr_def_exist, "name"), name) == 0) {
			print_error(MKE_ERROR_FATAL, sr_def, 0, "%s: duplicated name", name);
			sr_free(sr_def);
			return;
		}
	}
	sr_append(sr_defs, sr_def);
}

sr_t *
create_sr_mke_edexpr(ecm_uint32 lineno, char *edexpr)
{
	sr_t	*sr_mke_edexpr;
	ecm_uint32	edexpr_lineno;
	char	*errmsg;

	if (!edl_check_edexpr(edexpr, &edexpr_lineno, &errmsg)) {
		raise_error(MKE_ERROR_FATAL, lineno + edexpr_lineno, "%s", errmsg);
		ecm_free(errmsg);
	}

	sr_mke_edexpr = sr_create(ST_MKE_EDEXPR);
	sr_addc(sr_mke_edexpr, "edexpr", sr_set_val(sr_create(ST_STR), sr_val_str(edexpr)));
	add_src_info(sr_mke_edexpr, lineno);
	return sr_mke_edexpr;
}

sr_t *
add_section(ecm_uint32 lineno, const char *desc, const char *name,
	    sr_t *sr_sections, sr_t *sr_section)
{
	if (sr_add_child(sr_sections, name, sr_section) == NULL) {
		raise_error(MKE_ERROR_FATAL, lineno, "%s: multiple section is not allowed", desc);
		sr_free(sr_section);
	}
	return sr_sections;
}

ECMBOOL
make_spec_obj(const char *modname, sr_t *sr_sobj)
{
	char	*sobjname;
	int	fd;
	ECMBOOL	res = ECM_FALSE;

	if (dryrun_mode)
		return ECM_TRUE;

	ecm_asprintf(&sobjname, "%s.sobj", modname);
	if (ecm_creat(&fd, sobjname, ECM_P_RWUSR) == ECM_OK &&
	    eds_write_enc_sr(fd, sr_sobj, ENC_BUFSIZE)) {
		ecm_close(fd);
		res = ECM_TRUE;
	}
	else
		fprintf(stderr, "%s: Cannot write\n", sobjname);

	ecm_free(sobjname);
	sr_free(sr_sobj);

	return res;
}
